var GownFullHTMLRichEditAdapter = GownFullObjectAdapter.extend({
	keydown_handler: null,
	keyup_handler: null,
	keypress_handler: null,
	focus_handler: null,

	is_focus: false,
	stored_selection: null,

	constructor: function(obj)
	{
		this.base(obj);
		//this.obj = obj;
	},
	clone: function(obj)
	{
		return new GownFullHTMLRichEditAdapter(obj);
	},
	GetCursorXY: function()
	{
		var pos = JSVKBrowserExtension.getOffset(this.obj);
/*		try {
			var sel,range,node;

			sel = this.obj.contentWindow.getSelection();
			range = sel.getRangeAt(sel.rangeCount-1);
			node = range.startContainer;
			while(!node || lib.isUndefined(node.offsetLeft) || lib.isUndefined(node.offsetTop)) {
				node = node.parentNode;
			} 

			Debug.trace(2,'GownFullHTMLRichEditAdapter: GetCursorXY: Using Method 1');
			pos.x += node.offsetLeft;
			pos.y += node.offsetTop;
			return new Array(pos.x,pos.y);
		}
		catch(e) {}
*/
		try {
			var range = this.obj.contentWindow.document.selection.createRange();
			Debug.trace(2,'GownFullHTMLRichEditAdapter: GetCursorXY: Using Method 2');
			pos.x += range.offsetLeft;
			pos.y += range.offsetTop;
			return new Array(pos.x,pos.y);
		}
		catch(e) {}

		Debug.trace(0,'GownFullHTMLRichEditAdapter: GetCursorXY is not supported.');
		return null;
	},
	/*
           The code is copied from http://www.mozilla.org/editor/midas-spec.html
        */
	MozillaInsertNodeAtSelection: function(win,insertNode)
	{
		// get current selection
		var sel = win.getSelection();
		
		// get the first range of the selection
		// (there's almost always only one range)
		var range = sel.getRangeAt(0);
		
		// deselect everything
		sel.removeAllRanges();
		
		// remove content of current selection from document
		range.deleteContents();
		
		// get location of current selection
		var container = range.startContainer;
		var pos = range.startOffset;
		
		// make a new range for the new selection
		range=document.createRange();
		
		if (container.nodeType==3 && insertNode.nodeType==3) {
		
			// if we insert text in a textnode, do optimized insertion
			container.insertData(pos, insertNode.nodeValue);
			
			// put cursor after inserted text
			range.setEnd(container, pos+insertNode.length);
			range.setStart(container, pos+insertNode.length);
		} else {
			var afterNode;
			if (container.nodeType==3) {
			
				// when inserting into a textnode
				// we create 2 new textnodes
				// and put the insertNode in between
			
				var textNode = container;
				container = textNode.parentNode;
				var text = textNode.nodeValue;
			
				// text before the split
				var textBefore = text.substr(0,pos);
				// text after the split
				var textAfter = text.substr(pos);
			
				var beforeNode = document.createTextNode(textBefore);
				afterNode = document.createTextNode(textAfter);
			
				// insert the 3 new nodes before the old one
				container.insertBefore(afterNode, textNode);
				container.insertBefore(insertNode, afterNode);
				container.insertBefore(beforeNode, insertNode);
			
				// remove the old node
				container.removeChild(textNode);
				// by wonghang
				range.setEnd(afterNode, 0);
				range.setStart(afterNode, 0);

			} else {
			
				// else simply insert the node
				afterNode = container.childNodes[pos];
				container.insertBefore(insertNode, afterNode);
				// by wonghang
				range.setEnd(insertNode, insertNode.length);
				range.setStart(insertNode, insertNode.length);

			}
/* original		
			range.setEnd(afterNode, 0);
			range.setStart(afterNode, 0);
*/
		}
		
		sel.addRange(range);
	},
	SendRawHTML: function(obj,html)
	{
		try {
			var doc;
			var ifme = this.obj;

			if(ifme.document) doc = ifme.document;
			else if(ifme.contentDocument) doc = ifme.contentDocument;

			doc.execCommand('insertHTML',false,html);

			Debug.trace(2,"GownFullHTMLRichEditAdapter: SendRawHTML: Using method 1");
			return true;
		}
		catch(e) {}
		try {
			var sel = null;

			if(obj.nodeName && obj.nodeName.toLowerCase() == 'iframe') {
				Debug.trace(2,"GownFullHTMLRichEditAdapter: SendRawHTML: Got iframe element, switch to window");
				obj = obj.contentWindow;
			}
			// try to set focus...
			if(obj.focus) obj.focus();
			// try to restore selection
			this.RestoreSelection(this.stored_selection);

			if(obj.getSelection) sel = obj.getSelection();
			else if(obj.document && obj.document.selection) sel = obj.document.selection;

			var rng = sel.createRange();
			rng.pasteHTML(html);
			rng.collapse(false);
			rng.select();
			Debug.trace(2,"GownFullHTMLRichEditAdapter: SendRawHTML: Using method 2 (%s, nodeName=%s)",obj,obj.nodeName);
			this.stored_selection = this.GetSelection();
			return true;
		}
		catch(e) {}

		Debug.trace(0,"GownFullHTMLRichEditAdapter: SendRawHTML: Failure to send HTML to iframe, maybe current browser is not supported.");
		return false;
	},
	SendString: function(o,str)
	{
		if(GownFullBrowserDetect.current_engine == GownFullBrowserDetect.ENGINE_GECKO) {
			var text = document.createTextNode(str);
			var win = this.obj.contentWindow;
			try { this.MozillaInsertNodeAtSelection(win,text); }
			catch(e) {}
			return true;
		}
		else {
			str = str.replace(/&/g,'&amp;');
			str = str.replace(/</g,'&lt;');
			str = str.replace(/>/g,'&gt;');
	
			return this.SendRawHTML(o,str);
		}
	},
	SendHTML: function(o,html)
	{
		return this.SendRawHTML(o,html);
	},
	isHTML: function()
	{
		return true;
	},
	SetFocus: function()
	{
		try {
			this.obj.contentWindow.focus();
		}
		catch(e) {}
	},
	AttachHandler: function(keydown_handler,keypress_handler,keyup_handler,focus_handler)
	{
		var x = this;

		this.keydown_handler = keydown_handler;
		this.keyup_handler = keyup_handler;
		this.keypress_handler = keypress_handler;
		this.focus_handler = focus_handler;

		// special treatment for IE....
		if(GownFullBrowserDetect.current_browser == GownFullBrowserDetect.BROWSER_IE) {
			var win,doc;
			win = this.obj.contentWindow;
			doc = win.document;

			doc.GownFullObjectAdapter = this;
			if(doc.body) doc.body.GownFullObjectAdapter = this;

			// don't know why we cannot use attachEvent...
			doc.onkeydown = function() { return x.keydown_handler(win.event); }
			doc.onkeypress = function() {
				var b = x.keypress_handler(win.event); 
				if(b && x.is_focus) x.stored_selection = null; // invalidate selection if key is pressed
				return b;
			}
			doc.onkeyup = function() { return x.keyup_handler(win.event); }
/*
			this.obj.onfocus = function()
			{
				return x.focus_handler(window.event);
			}
*/
			doc.onselectionchange = function()
			{
				if(x.is_focus) x.stored_selection = x.GetSelection();
				return true;
			}
			this.obj.onfocus = function()
			{
				x.RestoreSelection(x.stored_selection);
				x.is_focus = true;
				x.stored_selection = x.GetSelection();
				return x.focus_handler(window.event);
			}
			this.obj.onblur = function()
			{
				x.is_focus = false;
				return true;
			}
			return true;
		}
		else {
			var doc;
			var obj = this.obj;

			if(obj.document) doc = obj.document;
			else if(obj.contentDocument) doc = obj.contentDocument;

			doc.GownFullObjectAdapter = this;
			if(doc.documentElement) doc.documentElement.GownFullObjectAdapter = this;

			obj = doc;

			if(GownFullBrowserDetect.use_key_addEventListener) {
				obj.addEventListener("keydown", function(e) { return x.keydown_handler(e); },false);
				obj.addEventListener("keypress", function(e) { return x.keypress_handler(e); },false);
				obj.addEventListener("keyup", function(e) { return x.keyup_handler(e); },false);
				obj.addEventListener("focus",function(e) { return x.focus_handler(e); },false);
			}
			else if(GownFullBrowserDetect.use_attachEvent) {
				obj.attachEvent("onkeydown", function(e) { return x.keydown_handler(e); });
				obj.attachEvent("onkeypress", function(e) { return x.keypress_handler(e); });
				obj.attachEvent("onkeyup", function(e) { return x.keyup_handler(e); });
				obj.attachEvent("onfocus",function(e) { return x.focus_handler(e); });
			}
			else {
				obj.onkeydown = function() { return x.keydown_handler(window.event); }
				obj.onkeypress = function() { return x.keypress_handler(window.event); }
				obj.onkeyup = function() { return x.keyup_handler(window.event); }
				obj.onfocus = function() { return x.focus_handler(window.event); }
			}
		}
	},
	GetHTMLDocument: function()
	{
		var o = this.obj;

		if(o.contentWindow) return o.contentWindow.document;
		else if(o.document) return o.document;
		else if(o.contentDocument) return o.contentDocument;
		else return null;
	},
	GetHTMLElement: function()
	{
		try {
			var sel,range,node;

			sel = this.obj.contentWindow.getSelection();
			range = sel.getRangeAt(0);
			node = range.startContainer;
			return node;
		}
		catch(e) {}
		Debug.trace(0,'GownFullHTMLRichEditAdapter: GetHTMLElement does not supported');
		return null;
	},
	GetHTMLElementById: function(id)
	{
		try {
			var doc;
			doc = this.obj.contentWindow.document;
			return doc.getElementById(id);
		}
		catch(e) {}
		Debug.trace(0,'GownFullHTMLRichEditAdapter: GetHTMLElementById does not supported');
		return null;
	},
	SetHTMLElementEventById: function(id,event,handler)
	{
		try {
			var doc;
			var obj;

			doc = this.obj.contentWindow.document;
			obj = doc.getElementById(id);
			
			if(GownFullBrowserDetect.use_addEventListener) {
				obj.addEventListener(event,handler,false);
			}
			else if(GownFullBrowserDetect.use_attachEvent) {
				obj.attachEvent("on" + event,handler);
			}
			else throw "Unsupported";
			return true;
		}
		catch(e) {}
		Debug.trace(0,'GownFullHTMLRichEditAdapter: SetHTMLElementEventById does not supported');
		return false;
	},
	GetSelection: function()
	{
		try { // should be happen only on IE
			var fwin = this.obj.contentWindow;
		
			return fwin.document.selection.createRange();
		}
		catch(e) {}
		return true;
	},
	RestoreSelection: function(sel)
	{
		try { // should be happen only on IE
			sel.select();
		}
		catch(e) {}
		return true;
	}
});
